package com.wyj.gateway.config;

import com.wyj.gateway.config.properties.BaseProperties;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.CollectionUtils;
import org.springframework.util.PathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

/**
 * TODO: api网关配置
 *
 * @author wuyijie
 * @date 2022/2/10 22:29
 */
@Configuration
@Slf4j
public class GatewayConfig {
    private final RedisTemplate<Object, Object> redisTemplate;

    private static Set<String> WHITELIST_API_SET;

    public GatewayConfig(BaseProperties baseProperties, RedisTemplate<Object, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
        if (baseProperties.getWhiteList() != null) {
            final BaseProperties.WhiteList whiteList = baseProperties.getWhiteList();
            if (!CollectionUtils.isEmpty(whiteList.getApi())) {
                WHITELIST_API_SET = new HashSet<>(whiteList.getApi());
                log.info("WHITELIST_API_SET={}", WHITELIST_API_SET);
            }
        }
    }

    @Bean(value = "hostKeyResolver")
    @Primary
    public KeyResolver hostKeyResolver(){
        return exchange -> Mono.just(Objects.requireNonNull(exchange.getRequest().getRemoteAddress()).getHostName());
    }
    @Bean(value = "userKeyResolver")
    public KeyResolver userKeyResolver(){
        return exchange -> Mono.just(Objects.requireNonNull(exchange.getRequest().getQueryParams().getFirst("userId")));
    }
    @Bean(value = "apiKeyResolver")
    public KeyResolver apiKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getPath().value());
    }

    @Bean
    @Order(-1)
    public GlobalFilter firstGlobalFilter(){
        return new TokenGlobalFilter();
    }
    @Bean
    @Order(0)
    public GlobalFilter secondGlobalFilter(){
        return new SecondGlobalFilter();
    }

    private class TokenGlobalFilter implements GlobalFilter, Ordered{
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            ServerHttpRequest request = exchange.getRequest();
            URI uri = request.getURI();
            PathMatcher pathMatcher = new AntPathMatcher();
            for (String ignoreUrl : WHITELIST_API_SET) {
                if (pathMatcher.match(ignoreUrl, uri.getPath())) {
                    // request = exchange.getRequest().mutate().header(AuthConstant.JWT_TOKEN_HEADER, "").build();
                    exchange = exchange.mutate().request(request).build();
                    return chain.filter(exchange);
                }
            }
            final HttpCookie httpCookie = exchange.getRequest().getCookies().getFirst("token");
            if (null == httpCookie){
                exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
                return exchange.getResponse().setComplete();
            }
            final String token = httpCookie.getValue();
            log.info("TokenCheckFilter token={}", token);
            if (StringUtils.isBlank(token) || Boolean.FALSE.equals(redisTemplate.hasKey(token))) {
                log.error("*****头部验证不通过，请在头部设置 token");
                //终止请求，直接回应
                exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
                return exchange.getResponse().setComplete();
            }
            log.info("FirstFilter前置拦截···");
            return chain.filter(exchange).then(Mono.fromRunnable(()->{
                log.info("FirstFilter后置拦截");
            }));
        }
        //值越小优先级越高
        @Override
        public int getOrder() {
            return HIGHEST_PRECEDENCE;
        }
    }

    @Slf4j
    private static class SecondGlobalFilter implements GlobalFilter, Ordered{
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            log.info("SecondFilter前置拦截···");
            return chain.filter(exchange).then(Mono.fromRunnable(()->{
                log.info("SecondFilter后置拦截");
            }));
        }
        //值越小优先级越高
        @Override
        public int getOrder() {
            return HIGHEST_PRECEDENCE+100;
        }
    }



}
